#include <iostream>

// Irrlicht and Cg Headers
#include "irrlicht.h"
#include <Cg/cg.h>

// IrrCg
#include "IrrCg.h"

// Irrlicht namespaces
using namespace irr;

using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

// Chernobyl Game Engine namespaces
using namespace IrrCg;

// Other namespaces
using namespace std;

IrrlichtDevice* Device = 0;
IVideoDriver* Driver = 0;
ISceneManager* SceneManager = 0;
stringw window = "";

class MultiTexturingCallBack : public ICgShaderConstantSetCallBack
{
public:
    CGparameter	texture0;
    CGparameter	texture1;

	virtual void OnSetConstants(ICgServices* services,CGprogram Vertex,CGprogram Pixel,const SMaterial &Material)
	{
        // Pixel Shader
        texture0 = cgGetNamedParameter(Pixel,"testTexture");
        services->EnableTexture( texture0,Material.getTexture(0));

        texture1 = cgGetNamedParameter(Pixel, "checkerTexture");
        services->EnableTexture( texture1,Material.getTexture(1));
	}
};

int main()
{
    printf("\n *** IrrCg MultiTexturing Example by Patryk Nadrowski ***\n\n");

    char i;

    // Select Irrlicht Driver
    video::E_DRIVER_TYPE DriverType;
	printf("\n Please select the driver you want for this demo:\n\n"\
		"  (a) Direct3D 9.0c\n  (b) OpenGL 1.5\n"\
		"  (otherKey) exit\n\n");

	std::cin >> i;

	switch(i)
	{
		case 'a':
            DriverType = EDT_DIRECT3D9;
            window = " Direct3D9 PS: [ps_2_0] ";
            break;

		case 'b':
            DriverType = EDT_OPENGL;
            window = " OpenGL PS: [arbfp1] ";
            break;

		default: return 1;
	}

	Device = createDevice(DriverType,dimension2d<u32>(800 , 600),32,false,false,false,0);
	Driver = Device->getVideoDriver();
	SceneManager = Device->getSceneManager();

    // Create Cg Programming Service
    ICgProgrammingServices* GPU = new ICgProgrammingServices(Device);

    // Create Cg Shader Material
    MultiTexturingCallBack* MTCB = new MultiTexturingCallBack();
    s32 CgMultiTextureMaterialType = GPU->addCgShaderMaterialFromFiles(CG_SOURCE,0,0,0,0,"../../cg/multitexturing.cg","main","arbfp1","ps_2_0",MTCB,EMT_SOLID);

    // Create Node
    IAnimatedMesh* mesh = SceneManager->getMesh("../../media/elephant.obj");
	ISceneNode* node = SceneManager->addAnimatedMeshSceneNode(mesh);
	node->setPosition(core::vector3df(0,0,0));
	node->setRotation(core::vector3df(0,0,0));
	node->setScale(core::vector3df(1,1,1));
	node->setAutomaticCulling(EAC_FRUSTUM_BOX);
	node->setMaterialFlag(video::EMF_LIGHTING, false);
	// Apply Cg Shader Material to Node
	node->setMaterialType((video::E_MATERIAL_TYPE)CgMultiTextureMaterialType);

    node->getMaterial(0).TextureLayer[0].Texture = Driver->getTexture("../../media/test.bmp");
    node->getMaterial(0).TextureLayer[1].Texture = Driver->getTexture("../../media/checker.bmp");

    ISceneNode* node2 = SceneManager->addCubeSceneNode(50);
	node2->setPosition(core::vector3df(0,0,-100));
	node2->setRotation(core::vector3df(0,0,0));
	node2->setScale(core::vector3df(1,1,1));
	node2->setAutomaticCulling(EAC_FRUSTUM_BOX);
	node2->setMaterialFlag(video::EMF_LIGHTING, false);
	// Apply Cg Shader Material to Node
	node2->setMaterialType((video::E_MATERIAL_TYPE)CgMultiTextureMaterialType);

    node2->getMaterial(0).TextureLayer[0].Texture = Driver->getTexture("../../media/checker.bmp");
    node2->getMaterial(0).TextureLayer[1].Texture = Driver->getTexture("../../media/test.bmp");

    // Create Camera
	scene::ICameraSceneNode* cam = SceneManager->addCameraSceneNodeFPS(0,100.0f,0.1f);
	cam->setPosition(core::vector3df(120,0,0));
	cam->setTarget(core::vector3df(0,0,0));

    // Hide Mouse Cursor
    Device->getCursorControl()->setVisible(false);

    // Last FPS
    int lastFPS = -1;

	while(Device->run())
    if (Device->isWindowActive())
	{
        // Begin Scene
		Driver->beginScene(true, true, video::SColor(255,0,0,0));

        // Draw All
        SceneManager->drawAll();

        // End Scene
		Driver->endScene();

		int fps = Driver->getFPS();
		int poly = Driver->getPrimitiveCountDrawn();

		if (lastFPS != fps)
		{
		    core::stringw str = "";
            str = L"Irrlicht Cg - MultiTexturing for";
            str += window;
            str += L" FPS: ";
            str += fps;
            str += L" Poly: ";
            str += poly;

            Device->setWindowCaption(str.c_str());
            lastFPS = fps;
		}
	}

	delete GPU;
	Device->drop();
	return 0;
}
